local _class = {}
local _instance = {}

local function inherit(cls, ...)
	--class method
	cls.new = function(c, ...)
		if _instance[c] ~=nil then
			return _instance[c]
		end
		local obj = {}
		obj.__cls = c
		setmetatable(obj, {__index = _class[c]})
		do
			local create
			create = function(c, ...)
				local components = rawget(c, '__components')
				for _, comp in ipairs(components) do
					create(comp, ...)
				end
				local init = rawget(_class[c], "init")
				if init then
					init(obj, ...)
				end
			end
			create(c, ...)
		end
		return obj
	end

	--class method
	cls.initInstance = function(c, ...)
		local obj = _instance[c]
		if not obj then
			obj = c:new(...)
			_instance[c] = obj
			setmetatable(c, {__index = obj})
		end
		return obj
	end

	cls.setClassData = function(c, k, v)
		local cdata = rawget(c, "__classData")
		cdata[k] = v
	end

	cls.getClassData = function(c, k)
		local cdata = rawget(c, "__classData")
		return cdata[k]
	end



	--class template cache
	local vtbl = _class[cls]
	--after this, all method to cls is defined for obj instance
	setmetatable(cls, {__newindex = function(t, k, v)
			vtbl[k] = v
	end})

	--obj method
	cls.super = function(obj, method, ...)
		local components = rawget(obj.__cls, '__components')
		for _, comp in ipairs(components) do
			local func = _class[comp][method]
			if func then
				func(obj, ...)
			end
		end
	end

	cls.getClassName = function(obj)
		local c = obj.__cls
		return c.getClassData(c, "class_name")
	end

	cls.getPackageName = function(obj)
		local c = obj.__cls
		return c.getClassData(c, "package_name")
	end

	cls.getFullClassName = function(obj)
		local cname = obj:getClassName()
		if not cname then return nil end
		local pname = obj:getPackageName()
		if not pname then return cname end
		return pname..'.'..cname
	end

	local supers = {...}
	if #supers > 0 then
		local comps = rawget(cls, '__components')
		for _, comp in ipairs(supers) do
			table.insert(comps, comp)
		end

		setmetatable(vtbl, {__index = function(t, k)
			local components = rawget(cls, '__components')
			for _, comp in ipairs(components) do
				local ret = _class[comp][k]
				if ret ~= nil then
					vtbl[k] = ret
					return ret
				end
			end
		end})
	end
	
	return cls
end

local function class(...)
	local cls = {}
	
	local vtbl = {}
	_class[cls] = vtbl

	--基类们
	cls.__components = {}
	--classData
	cls.__classData = {}

	inherit(cls, ...)
	return cls
end

return class
